【CodeMirror】如何构建自己的线上编辑器

您所在的位置:网站首页 yaml 语法检测 js 【CodeMirror】如何构建自己的线上编辑器

【CodeMirror】如何构建自己的线上编辑器

2023-10-25 09:39| 来源: 网络整理| 查看: 265

当我们构建好语法高亮后,我们发现当编辑器上的内容并没有命中我们匹配的规则,或者其语义并不能被正确解析。我们需要将异常的地方标示出来,并且给予信息提示。基于此,我们可以通过自定义Lint的方式去实现这个功能。如果需要实现以下功能,我们需要先集成CodeMirror中提供的lint插件,然后基于插件通过registerHelper API去定义我们的lint功能。

CodeMirror Lint插件集成

关于Lint插件的集成,我们需要两个步骤。

引入codemirror/addon/lint/lint.js和lint.css文件。 实例化配置项新增lint: true的选项 为什么要集成lint.js 和lint.css文件 lint.js和lint.css文件内部实现了自定义配置项lint的功能 通过接口方式定义了外部和lint.js的交互,主要是返回以{message, severity, from, to}对象数组格式的数据来实现侧边栏的异常描述和具体位置异常提示 通过不同配置满足同步或者异步的处理 为什么要配置lint:true这个选项

lint这个选项是lint.js中通过defineOption的方式去扩展CodeMirror的配置项,通过初始化或者setOption时调用回调去启用lint。

CodeMirror.defineOption("lint", false, function(cm, val, old) { if (old && old != CodeMirror.Init) { clearMarks(cm); if (cm.state.lint.options.lintOnChange !== false) cm.off("change", onChange); CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); clearTimeout(cm.state.lint.timeout); delete cm.state.lint; } if (val) { var gutters = cm.getOption("gutters"), hasLintGutter = false; for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; var state = cm.state.lint = new LintState(cm, val, hasLintGutter); if (state.options.lintOnChange) cm.on("change", onChange); if (state.options.tooltips != false && state.options.tooltips != "gutter") CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); startLinting(cm); } }); 如何实现Lint

先上代码。

CodeMirror.registerHelper("lint", MODE_NAME, (text: string, options: CodeMirror.EditorConfiguration, cm:CodeMirror) => { const lintList: CodeMirrorVerifyError[] = []; try { // 业务实现,存在异常通过Error抛出 valid(text); } catch (e: unknown) { lintList.push(e as CodeMirrorVerifyError); } return lintList; });

这里,我们通过CodeMirror的registHelper方法去定义lint。其中这里包含了3个参数

type。CodeMirror的命名空间,由于我们定义的是lint,所以赋值为'lint' name。这里需要注意的是,我们的name必须和我们在实例化使用的mode name必须一致,否则lint内部在调用getHelper时,会找不到对于的lint方法 回调函数cb。其中参数为内容字符串、选项对象和编辑器实例。并且需要返回上述说的约定数组{message, severity, from, to}数组。其中message为异常信息、severity时异常级别,默认为error。from和to为异常的起始位置和结束位置,类型为CodeMirror.Pos。

我们可以通过getHelper源码可以看到getHelper的实现基于getHelper。而getHelpers首先会根据type获取列表,然后会获取当前mode,通过mode name去取出匹配的函数列表。

getHelper: function(pos, type) { return this.getHelpers(pos, type)[0] }, getHelpers: function(pos, type) { let found = [] if (!helpers.hasOwnProperty(type)) return found let help = helpers[type], mode = this.getModeAt(pos) if (typeof mode[type] == "string") { if (help[mode[type]]) found.push(help[mode[type]]) } else if (mode[type]) { for (let i = 0; i < mode[type].length; i++) { let val = help[mode[type][i]] if (val) found.push(val) } } else if (mode.helperType && help[mode.helperType]) { found.push(help[mode.helperType]) } else if (help[mode.name]) { found.push(help[mode.name]) } for (let i = 0; i < help._global.length; i++) { let cur = help._global[i] if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) found.push(cur.val) } return found },

这样,我们就基本可以实现我们自定义的Lint校验了。当然,如果你想配置不同的图标和样式,可以通修改css文件覆盖CodeMirror-lint-markers相关的样式

总结

总的来说,配置lint是比较简单的,复杂的主要时你对lint的校验规则,其中涉及了词法分析、语法分析、语义分析等实现。当然,你可以可以通过babel插件去解析对应的语法来实现lint自定义。

2022.08.02

木更



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3